package com.vita.core2;

import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ExecutionException;

public class Helper {

    /**
     * 抢夺上行目标
     *
     * 失去上升有效目标返回false
     * 失去有效目标（同时满足时失去）：
     * 1、正在上升的电梯数量大于目标楼层的数量
     * 2、本电梯最小距离小于其他电梯最小距离（仅外部上升集合中比）
     */
    public static boolean isMoreUpTarget(Central central,int nowFloor){
        Machine[] ms = central.getMs();

        TreeSet<Integer> newUp = new TreeSet<>(Integer::compareTo);
        for(int i:central.getUpList()){
            if(i>=nowFloor){
                newUp.add(i);
            }
        }
        for(int i:central.getDwList()){
            if(i>nowFloor){
                newUp.add(i);
            }
        }

        int min = newUp.first();

        // 正在抢夺上升资源的电梯
        Set<Machine> upms = new HashSet<>();
        for(Machine m:ms){
            if(m.getState()==1){
                // 比当前电梯所在楼层高，比最高目标楼层低的加入
                if(m.getNowFloor() >= nowFloor && m.getNowFloor() < min){
                    upms.add(m);
                }
            }
        }

        if(upms.size()>newUp.size()){
            // 计算这几个上升的是否有本电梯快（与最小值比）
            for(Machine m: upms){
                if((min - m.getNowFloor())<(min - nowFloor)){
                    // 失去有效目标
                    return false;
                }
            }
        }
        
        return true;

    }

    /**
     * 抢夺下行目标
     *
     * 失去下行有效目标返回false
     * 失去有效目标（同时满足时失去）：
     * 1、正在下行的电梯数量大于目标楼层的数量
     * 2、本电梯最小距离小于其他电梯最小距离（仅外部下行集合中比）
     */
    public static boolean isMoreDwTarget(Central central,int nowFloor){
        Machine[] ms = central.getMs();
        TreeSet<Integer> newDw = new TreeSet<>(Integer::compareTo);
        for(int i:central.getUpList()){
            if(i<nowFloor){
                newDw.add(i);
            }
        }
        for(int i:central.getDwList()){
            if(i<=nowFloor){
                newDw.add(i);
            }
        }

        int max = newDw.first();

        Set<Machine> dwms = new HashSet<>();
        for(Machine m:ms){
            if(m.getState()==-1){
                if(m.getNowFloor() <= nowFloor && m.getNowFloor() > max){
                    dwms.add(m);
                }
            }
        }

        if(dwms.size()>newDw.size()){
            for(Machine m: dwms){
                if((m.getNowFloor() - max)<(nowFloor - max)){
                    return false;
                }
            }
        }
        
        return true;
    }

    /**
     * 根据最短距离，计算上升还是下降
     */
    public static int isUpOrDw(Machine m,Central central){
        int nowFloor = m.getNowFloor();

        TreeSet<Integer> upList = central.getUpList();
        TreeSet<Integer> dwList = central.getDwList();
        TreeSet<Integer> innerList = m.getInnerList();

        if(innerList.isEmpty() && upList.isEmpty() && dwList.isEmpty()){
            return 0;
        }

        // 判断最短距离是需要升还是降

        // 上升请求中，比当前楼层大的值集合
        TreeSet<Integer> newUp = new TreeSet<>(Integer::compareTo);
        for(Integer i:upList){
            if(i>=nowFloor){
                newUp.add(i);
            }
        }
        for(Integer i:innerList){
            if(i>nowFloor){
                newUp.add(i);
            }
        }
        for(Integer i:dwList){
            if(i>nowFloor){
                newUp.add(i);
            }
        }

        // 下降请求中，比当前楼层小的值集合
        TreeSet<Integer> newDw = new TreeSet<>(Comparator.reverseOrder());
        for(Integer i:dwList){
            if(i<=nowFloor){
                newDw.add(i);
            }
        }
        for(Integer i:innerList){
            if(i<nowFloor){
                newDw.add(i);
            }
        }
        for(Integer i:upList){
            if(i<nowFloor){
                newDw.add(i);
            }
        }

        int upMin = newUp.pollFirst();
        int dwMin = newDw.pollFirst();

        // 谁的最近距离更短，就上行或下行
        if(upMin<=dwMin){
            return 1;
        }else{
            return -1;
        }


    }

    /**
     * 是否继续
     *
     * 1、有最小距离     haveMinDistance true
     * 2、有有效目标     haveEffDistance true
     * 3、若正向不满住1、2，测反向
     */
    public static boolean isContinue(Machine m,Central central){
        // 继续？
        if(Helper.haveEffDistance(m,central)){
            return true;
        }
        // 反向
        m.setState(-m.getState());
        return Helper.haveEffDistance(m,central);
                
    }

    /**
     * 获取有效目标
     */
    public static boolean haveEffDistance(Machine m,Central central){
        int state = m.getState();
        int nowFloor = m.getNowFloor();
        // 1、有最小距离
        if(Helper.haveMinDistance(m,central)){
            // 2、有有效目标，返回true

            if(state == 1){
                // 外部有更多的目标
                if(isMoreUpTarget(central, nowFloor)){
                    return true;
                }

                // 内部有更多的目标
                if(haveBiger(m.getInnerList(),nowFloor)){
                    return true;
                }
            }else if(state == -1){
                // 外部有更多的目标
                if(isMoreDwTarget(central, nowFloor)){
                    return true;
                }

                // 内部有更多的目标
                if(haveLiter(m.getInnerList(),nowFloor)){
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 是否有最小距离
     */
    public static boolean haveMinDistance(Machine m,Central central){
        TreeSet<Integer> upList = central.getUpList();
        TreeSet<Integer> dwList = central.getDwList();
        TreeSet<Integer> innerList = m.getInnerList();

        int nowFloor = m.getNowFloor();
        
        if (m.getState() == 1) {
            // 上行时，有比当前楼层更大的值，就继续上行

            if(haveBiger(upList, nowFloor)){
                return true;
            }

            if(haveBiger(innerList, nowFloor)){
                return true;
            }

            if(haveBiger(dwList, nowFloor)){
                return true;
            }
        }else if (m.getState() == -1){
            // 下行时，有比当前楼层更小的值就继续下行

            if(haveLiter(upList, nowFloor)){
                return true;
            }

            if(haveLiter(innerList, nowFloor)){
                return true;
            }

            if(haveLiter(dwList, nowFloor)){
                return true;
            }
        }

        return false;
    }

    private static boolean haveBiger(TreeSet<Integer> list,int nowFloor){
        for(int i : list){
            if(i>nowFloor){
                return true;
            }
        }
        return false;
    }

    private static boolean haveLiter(TreeSet<Integer> list,int nowFloor){
        for(int i : list){
            if(i<nowFloor){
                return true;
            }
        }
        return false;
    }

    /**
     * 判断当前这一层是否需要打开,需要就移除
     */
    public static boolean isOpen(TreeSet<Integer> list1,TreeSet<Integer> list2,int nowFloor){
        // 两个都remove，其中一个或两true返回true
        if(list1.remove(nowFloor) | list2.remove(nowFloor)){
            return true;
        }
        return false;
    }

    /**
     * 电梯外部按下一个新楼层(上行)
     */
    public static Machine upFloor(int newFloor, Central central) throws InterruptedException, ExecutionException {
        TreeSet<Integer> list = central.getUpList();
        Machine m = null;
        // 加入list
        if (list.add(newFloor)) {
            // 加入成功，将可用的电梯状态设为 1
            m = liveUpMachine(newFloor,central);
        }
        return m;
    }

    /**
     * 电梯外部按下一个新楼层(下行)
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static Machine dwFloor(int newFloor, Central central) throws InterruptedException, ExecutionException {
        TreeSet<Integer> list = central.getDwList();
        Machine m = null;
        // 加入list
        if (list.add(newFloor)) {
            // 加入成功，发起调用电梯请求
            m = liveDwMachine(newFloor, central);
        }
        return m;
    }

    /**
     * 获取目标电梯，并设置目标电梯状态 (从静止的电梯中选取)
     * 发起上升调用电梯请求
     * 
     * 如果目标电梯就在当前楼层，也改变电梯状态，并调用电梯
     */
    public static Machine liveUpMachine(int newFloor, Central central) throws InterruptedException, ExecutionException {
        // 寻找向上的电梯，有就获取最短距离
        Machine[] ms = central.getMs();
        // 最小距离
        Integer min = null;
        // 目标电梯
        Machine liveMachine = null;
        for (Machine m : ms) {
            int state = m.getState();
            if (state == 0 ) {
                // 电梯当前楼层
                int mNowFloor = m.getNowFloor();
                int abs = Math.abs(mNowFloor-newFloor);
                // 获取上升或静止中最短距离者
                if (min == null) {
                    min = abs;
                    liveMachine = m;
                } else {
                    if(abs < min){
                        min = abs;
                        liveMachine = m;
                    }
                }
            }
        }

        // 将目标电梯改为上升
        if(liveMachine != null) {
            // 再次判断电梯状态，避免在这个过程中电梯状态已经发生了改变
            if (liveMachine.getState() == 0){
                liveMachine.setState(1);

                // 调动电梯
                liveMachine.run().get();
            }else{
                // 如果电梯状态发生了改变重新获取
                liveMachine = liveUpMachine(newFloor,central);
            }
        }
        return liveMachine;
    }


    /**
     * 发起下降调用电梯请求
     */
    public static Machine liveDwMachine(int newFloor, Central central) throws InterruptedException, ExecutionException {
        // 寻找向上的电梯，有就获取最短距离
        Machine[] ms = central.getMs();
        // 最小距离
        Integer min = null;
        // 循环获取最短距离的电梯(从正在下降或静止的电梯中选取)
        Machine liveMachine = null;
        for (Machine m : ms) {
            // 如果有向上的电梯
            int state = m.getState();
            if (state == 0 ) {
                // 电梯当前楼层
                int mNowFloor = m.getNowFloor();
                int abs = Math.abs(mNowFloor-newFloor);
                // 获取上升或静止中最短距离者
                if (min == null) {
                    min = abs;
                    liveMachine = m;
                } else {
                    if(abs < min){
                        min = abs;
                        liveMachine = m;
                    }
                }
            }
        }

        // 有目标电梯，且目标电梯处于静止状态时
        // 将目标电梯改为下降
        if(liveMachine != null) {
            // 再次判断电梯状态，避免在这个过程中电梯状态已经发生了改变
            if (liveMachine.getState() == 0){
                liveMachine.setState(-1);

                // 调动电梯
                liveMachine.run().get();
            }else{
                // 如果电梯状态发生了改变重新获取
                liveMachine = liveDwMachine(newFloor,central);
            }
        }

        return liveMachine;
    }

}
